package com.villaday.idf.util;

import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.media.ThumbnailUtils;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import androidx.annotation.IntRange;
import android.text.TextUtils;


import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;

/**
 * Bitmap处理工具类
 */
public class BitMapUtil {

    public static final String CACHE_DIR = Environment.getExternalStorageDirectory() +
            "/Android/data/cn.com.zlct.huiminegou/cache";//缓存路径

    /**
     * 图片二次采样 -- 图片路径
     */
    public static Bitmap decodeBitmap(String bitmapFile, int scaleWidth, int scaleHeight){
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;//表示只解码图片的边缘信息，用来得到图片的宽高
        BitmapFactory.decodeFile(bitmapFile, options);
        int oldWidth = options.outWidth;
        int oldHeight = options.outHeight;
        int bWidth = oldWidth / scaleWidth;
        int bHeight = oldHeight / scaleHeight;
        if (oldWidth > scaleWidth || oldHeight > scaleHeight) {
            int size = bWidth < bHeight ? bWidth : bHeight;
            if (size == 0) {
                size = (bWidth + bHeight) / 2;
            }
            options.inSampleSize = size;
        }
        options.inJustDecodeBounds = false;
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        return BitmapFactory.decodeFile(bitmapFile, options);
    }

    /**
     * 图片二次采样 -- Uri
     */
    public static Bitmap decodeBitmap(Context context, Uri uri, int scaleWidth, int scaleHeight) throws Exception{
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;//表示只解码图片的边缘信息，用来得到图片的宽高
        BitmapFactory.decodeStream(context.getContentResolver().openInputStream(uri), null, options);
        int oldWidth = options.outWidth;
        int oldHeight = options.outHeight;
        int bWidth = oldWidth / scaleWidth;
        int bHeight = oldHeight / scaleHeight;
        if (oldWidth > scaleWidth || oldHeight > scaleHeight) {
            int size = bWidth < bHeight ? bWidth : bHeight;
            if (size == 0) {
                size = (bWidth + bHeight) / 2;
            }
            options.inSampleSize = size;
        }
        options.inJustDecodeBounds = false;
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        return BitmapFactory.decodeStream(context.getContentResolver().openInputStream(uri), null, options);
    }

    /**
     * 图片二次采样并存为图片
     */
    public static File saveBitmap2File(String bitmapFile, int scaleWidth, int scaleHeight){
        Bitmap bitmap = decodeBitmap(bitmapFile, scaleWidth, scaleHeight);
        String filePath = CACHE_DIR + "/" + bitmapFile.hashCode() + ".jpg";
        return saveBitmap2File(bitmap, filePath);
    }

    /**
     * 图片二次采样并存为图片
     */
    public static File saveBitmap2File(Bitmap bitmap, String filePath){
        File file = new File(filePath);
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdir();
        }
        try {
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
            bos.flush();
            bos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return file;
    }

    /**
     * 图片二次采样 -- 裁剪成方形
     */
    public static Bitmap decodeBitmap(Bitmap bitmap, int scaleWidth, int scaleHeight){
        int min = scaleWidth < scaleHeight ? scaleWidth : scaleHeight;
        return ThumbnailUtils.extractThumbnail(bitmap, min, min);
    }

    /**
     * 图片二次采样 -- 裁剪成方形
     */
    public static Bitmap decodeBitmap(Bitmap bitmap){
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;//表示只解码图片的边缘信息，用来得到图片的宽高
        BitmapFactory.decodeStream(Bitmap2IS(bitmap), null, options);
        return decodeBitmap(bitmap, options.outWidth, options.outHeight);
    }

    /**
     * 图片二次采样
     */
    public static Bitmap decodeBitmap4Review(Bitmap bitmap, int scaleWidth, int scaleHeight){
        int oldWidth = bitmap.getWidth();
        int oldHeight = bitmap.getHeight();
        int bWidth = oldWidth / scaleWidth;
        int bHeight = oldHeight / scaleHeight;
        int inSampleSize = bWidth < bHeight ? bWidth : bHeight;
        if (inSampleSize < 2) {
            inSampleSize = 2;
        }
        return ThumbnailUtils.extractThumbnail(bitmap, oldWidth / inSampleSize, oldHeight / inSampleSize);
    }

    /**
     * 图片转Bitmap
     */
    public static Bitmap getBitmap(String bitmapFile){
        return BitmapFactory.decodeFile(bitmapFile);
    }

    /**
     * 图片转Bitmap
     */
    public static Bitmap getBitmap(String bitmapFile, int inSampleSize){
        return BitmapFactory.decodeFile(bitmapFile, getBitmapOption(inSampleSize));
    }

    /**
     * 获取bitmap大小
     */
    public static int getBitmapSize(Bitmap bitmap){
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){    //API 19
            return bitmap.getAllocationByteCount();
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1){//API 12
            return bitmap.getByteCount();
        }
        return bitmap.getRowBytes() * bitmap.getHeight();
    }

    /**
     * Bitmap转byte[]
     */
    public static byte[] Bitmap2Bytes(Bitmap bm){
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bm.compress(Bitmap.CompressFormat.PNG, 100, baos);
        return baos.toByteArray();
    }

    /**
     * byte[]转Bitmap
     */
    public static Bitmap Bytes2Bitmap(byte[] b){
        if (b.length != 0){
            return BitmapFactory.decodeByteArray(b, 0, b.length);
        } else {
            return null;
        }
    }

    public static InputStream Bitmap2IS(Bitmap bm){
        ByteArrayOutputStream baos = Bitmap2BAOS(bm);
        InputStream is = new ByteArrayInputStream(baos.toByteArray());
        return is;
    }

    public static ByteArrayOutputStream Bitmap2BAOS(Bitmap bm){
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bm.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        return baos;
    }

    /**
     * Uri转Bitmap
     */
    public static Bitmap Uri2Bitmap(Context context, Uri uri){
        try {
            Bitmap bitmap = decodeBitmap(context, uri, PhoneUtil.getPhoneWidth(context) / 4,
                    PhoneUtil.getPhoneHeight(context) / 4);
            if (getBitmapSize(bitmap) > 512 * 1024L) {
                return decodeBitmap(bitmap, PhoneUtil.getPhoneWidth(context) / 4,
                        PhoneUtil.getPhoneHeight(context) / 4);
            } else {
                return bitmap;
            }
        } catch (Exception e) {
            e.printStackTrace();
            String path = getPath(context, uri);
            File file = new File(path);
            if (file.exists() && file.isFile() && file.length() > 128 * 1024L) {
                return getBitmap(path, (int) (file.length() / (128 * 1024L) + 1));
            }
            return getBitmap(path);
        }
    }

    /**
     * Uri转Bitmap 用于评论
     */
    public static Bitmap Uri2Bitmap4Big(Context context, Uri uri){
        try {
            Bitmap bitmap = decodeBitmap(context, uri, PhoneUtil.getPhoneWidth(context) / 3,
                    PhoneUtil.getPhoneHeight(context) / 3);
            if (getBitmapSize(bitmap) > 768 * 1024L) {
                return decodeBitmap4Review(bitmap, PhoneUtil.getPhoneWidth(context) / 3,
                        PhoneUtil.getPhoneHeight(context) / 3);
            } else {
                return bitmap;
            }
        } catch (Exception e) {
            e.printStackTrace();
            String path = getPath(context, uri);
            File file = new File(path);
            if (file.exists() && file.isFile() && file.length() > 196 * 1024L) {
                return getBitmap(path, (int) (file.length() / (196 * 1024L) + 1));
            }
            return getBitmap(path);
        }
    }

    public static String getPath(Context context, Uri uri) {
        String[] projection = {MediaStore.Images.Media.DATA };
        Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null);
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        return cursor.getString(column_index);
    }

    private static BitmapFactory.Options getBitmapOption(int inSampleSize){
        System.gc();
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inPurgeable = true;
        options.inSampleSize = inSampleSize;
        return options;
    }
//
//    /**
//     * 生成二维码
//     */
//    public static Bitmap createQRImage(String url, int qrSize){
//        if (TextUtils.isEmpty(url)) {
//            return null;
//        }
//
//        // 生成二维码的配置信息
//        HashMap<EncodeHintType, Object> hints = new HashMap<>();
//        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
//        // 容错等级，实现中心Logo
//        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.Q);
//        //设置白边
//        hints.put(EncodeHintType.MARGIN, 1);
//        // 使用 QRCodeWriter 来生成 黑白 位矩阵
//        QRCodeWriter writer = new QRCodeWriter();
//
//        try {
//            // 编码矩阵
//            BitMatrix matrix = writer.encode(url, BarcodeFormat.QR_CODE, qrSize, qrSize, hints);
//            // 获取矩阵的宽高
//            int width = matrix.getWidth();
//            int height = matrix.getHeight();
//            // 每一个像素，转换为一维数组
//            int[] pixels = new int[width * height];
//
//            for (int y = 0; y < height; y++) {  // 每一行
//                int offset = y * width;
//                for (int x = 0; x < width; x++) {
//                    pixels[offset + x] = matrix.get(x, y) ? Color.BLACK : Color.WHITE;
//                }
//            }
//
//            Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
//            bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
//            return bitmap;
//        } catch (WriterException e) {
//            e.printStackTrace();
//        }
//        return null;
//    }
    /**
     * 质量压缩方法
     *
     * @param image
     * @return
     */
   /* public static Bitmap compressImage(Bitmap image,long bitmapSize) {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法，这里100表示不压缩，把压缩后的数据存放到baos中
        int options = 100;
        while (baos.toByteArray().length / 1024 > bitmapSize) {
            int i = baos.toByteArray().length / 1024;
            LogeUtil.e("i",i+"dd");
            //循环判断如果压缩后图片是否大于100kb,大于继续压缩
            baos.reset();//重置baos即清空baos
            //第一个参数 ：图片格式 ，第二个参数： 图片质量，100为最高，0为最差  ，第三个参数：保存压缩后的数据的流
            image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%，把压缩后的数据存放到baos中
            options -= 10;//每次都减少10
        }
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中
        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream数据生成图片
        return bitmap;
    }*/


    /**
     * Bitmap 转 byte[]
     * @param bitmap 待转bitmap
     * @return 成功-byte[] 失败-null
     */
    public static byte[] bitmap2Bytes(Bitmap bitmap) {
        ByteArrayOutputStream byteArrayOutputStream = null;
        if(bitmap != null && !bitmap.isRecycled()) {
            try {
                byteArrayOutputStream = new ByteArrayOutputStream();
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);
                if(byteArrayOutputStream.toByteArray() == null) {
                }
                return byteArrayOutputStream.toByteArray();
            } catch (Exception e) {
            } finally {
                if(byteArrayOutputStream != null) {
                    try {
                        byteArrayOutputStream.close();
                    } catch (IOException var14) {
                        ;
                    }
                }
            }

            return null;
        } else {
            return null;
        }
    }

    /**
     * 压缩图片到指定byte大小 (在保证质量的情况下尽可能压缩 不保证压缩到指定字节)
     * @param datas 图片byte格式
     * @param byteCount 指定压缩到字节数
     * @return 压缩后的byte[] (不保证压缩到指定字节)
     */
    public static byte[] compressBitmap(byte[] datas, int byteCount) {
        boolean isFinish = false;
        if(datas != null && datas.length > byteCount) {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            Bitmap tmpBitmap = BitmapFactory.decodeByteArray(datas, 0, datas.length);
            int times = 1;
            double percentage = 1.0D;

            while(!isFinish && times <= 10) {
                outputStream.reset();
                percentage = Math.pow(0.8D, (double)times);
                int compress_datas = (int)(100.0D * percentage);
                tmpBitmap.compress(Bitmap.CompressFormat.JPEG, compress_datas, outputStream);
                if(outputStream != null && outputStream.size() < byteCount) {
                    isFinish = true;
                } else {
                    ++times;
                }
            }

            if(outputStream != null) {
                byte[] outputStreamByte = outputStream.toByteArray();
                if(!tmpBitmap.isRecycled()) {
                    tmpBitmap.recycle();
                }

                if(outputStreamByte.length > byteCount) {
                }

                return outputStreamByte;
            }
        }

        return datas;
    }

    /**
     * 压缩图片到指定byte大小 (在保证质量的情况下尽可能压缩 不保证压缩到指定字节)
     * @param bitmap 图片
     * @param byteCount 指定压缩到字节数
     * @return 压缩后的byte[] (不保证压缩到指定字节)
     */
    public static byte[] compressBitmap(Bitmap bitmap, int byteCount) {
        //return compressBitmap(bitmap2Bytes(bitmap), byteCount);

        return compressQualityBitmap(bitmap,byteCount);
    }


    /**
     * 第一种：质量压缩法
     * @param image     目标原图
     * @param maxSize   最大的图片大小
     * @return          bitmap，注意可以测试以下压缩前后bitmap的大小值
     */
    public static Bitmap compressImage(Bitmap image , long maxSize) {
        int byteCount = image.getByteCount();
        LogeUtil.e("yc压缩图片","压缩前大小"+byteCount);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        // 把ByteArrayInputStream数据生成图片
        Bitmap bitmap = null;
        // 质量压缩方法，options的值是0-100，这里100表示原来图片的质量，不压缩，把压缩后的数据存放到baos中
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        int options = 90;
        // 循环判断如果压缩后图片是否大于maxSize,大于继续压缩
        while (baos.toByteArray().length  > maxSize) {
            // 重置baos即清空baos
            baos.reset();
            // 这里压缩options%，把压缩后的数据存放到baos中
            image.compress(Bitmap.CompressFormat.JPEG, options, baos);
            // 每次都减少10，当为1的时候停止，options<10的时候，递减1
            if(options == 1){
                break;
            }else if (options <= 10) {
                options -= 1;
            } else {
                options -= 10;
            }
        }
        byte[] bytes = baos.toByteArray();
        if (bytes.length != 0) {
            // 把压缩后的数据baos存放到bytes中
            bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
            int byteCount1 = bitmap.getByteCount();
            LogeUtil.e("yc压缩图片","压缩后大小"+byteCount1);
        }
        return bitmap;
    }
    public static byte[] compressQualityBitmap(Bitmap bitmap, int topLimit) {
        if(bitmap != null && topLimit > 0) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int options = 100;
            bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos);

            while(baos.toByteArray().length > topLimit ) {
                baos.reset();
                if (options<=5){
                    options -= 1 ;

                }else {
                    options -= 5;

                }
                bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos);
            }

            byte[] bitmapArray = baos.toByteArray();

            try {
                baos.close();
                baos = null;
            } catch (IOException var14) {
                ;
            } finally {
                if(baos != null) {
                    try {
                        baos.close();
                        baos = null;
                    } catch (IOException var13) {
                        ;
                    }
                }

                return bitmapArray;
            }
        } else {
            return null;
        }
    }

    /**
     * 第一种：质量压缩法
     *
     * @param src           源图片
     * @param maxByteSize   允许最大值字节数
     * @param recycle       是否回收
     * @return              质量压缩压缩过的图片
     */
    public static Bitmap compressByQuality(final Bitmap src, final long maxByteSize, final boolean recycle) {
        if (src == null || src.getWidth() == 0 || src.getHeight() == 0 || maxByteSize <= 0) {
            return null;
        }
        LogeUtil.e("yc压缩图片","压缩前大小"+src.getByteCount());
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        src.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        byte[] bytes;
        if (baos.size() <= maxByteSize) {// 最好质量的不大于最大字节，则返回最佳质量
            bytes = baos.toByteArray();
        } else {
            baos.reset();
            src.compress(Bitmap.CompressFormat.JPEG, 0, baos);
            if (baos.size() >= maxByteSize) { // 最差质量不小于最大字节，则返回最差质量
                bytes = baos.toByteArray();
            } else {
                // 二分法寻找最佳质量
                int st = 0;
                int end = 100;
                int mid = 0;
                while (st < end) {
                    mid = (st + end) / 2;
                    baos.reset();
                    src.compress(Bitmap.CompressFormat.JPEG, mid, baos);
                    int len = baos.size();
                    if (len == maxByteSize) {
                        break;
                    } else if (len > maxByteSize) {
                        end = mid - 1;
                    } else {
                        st = mid + 1;
                    }
                }
                if (end == mid - 1) {
                    baos.reset();
                    src.compress(Bitmap.CompressFormat.JPEG, st, baos);
                }
                bytes = baos.toByteArray();
            }
        }
        if (recycle && !src.isRecycled()){
            src.recycle();
        }
        Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
        LogeUtil.e("yc压缩图片","压缩后大小"+bitmap.getByteCount());
        return bitmap;
    }


    /**
     * 第一种：质量压缩法
     *
     * @param src     源图片
     * @param quality 质量
     * @param recycle 是否回收
     * @return 质量压缩后的图片
     */
    public static Bitmap compressByQuality(final Bitmap src, @IntRange(from = 0, to = 100) final int quality, final boolean recycle) {
        if (src == null || src.getWidth() == 0 || src.getHeight() == 0) {
            return null;
        }
        LogeUtil.e("yc压缩图片","压缩前大小"+src.getByteCount());
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        src.compress(Bitmap.CompressFormat.JPEG, quality, baos);
        byte[] bytes = baos.toByteArray();
        if (recycle && !src.isRecycled()) {
            src.recycle();
        }
        Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
        LogeUtil.e("yc压缩图片","压缩后大小"+bitmap.getByteCount());
        return bitmap;
    }
    /**
     * 第二种：按采样大小压缩
     *
     * @param src        源图片
     * @param sampleSize 采样率大小
     * @param recycle    是否回收
     * @return 按采样率压缩后的图片
     */
    public static Bitmap compressBySampleSize(final Bitmap src, final int sampleSize, final boolean recycle) {
        if (src == null || src.getWidth() == 0 || src.getHeight() == 0) {
            return null;
        }
        LogeUtil.e("yc压缩图片","压缩前大小"+src.getByteCount());
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = sampleSize;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        src.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        byte[] bytes = baos.toByteArray();
        if (recycle && !src.isRecycled()) {
            src.recycle();
        }
        Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
        LogeUtil.e("yc压缩图片","压缩后大小"+bitmap.getByteCount());
        return bitmap;
    }


    /**
     * 第二种：按采样大小压缩
     *
     * @param src       源图片
     * @param maxWidth  最大宽度
     * @param maxHeight 最大高度
     * @param recycle   是否回收
     * @return 按采样率压缩后的图片
     */
    public static Bitmap compressBySampleSize(final Bitmap src, final int maxWidth, final int maxHeight, final boolean recycle) {
        if (src == null || src.getWidth() == 0 || src.getHeight() == 0) {
            return null;
        }
        LogeUtil.e("yc压缩图片","压缩前大小"+src.getByteCount());
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        src.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        byte[] bytes = baos.toByteArray();
        BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
        options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight);
        options.inJustDecodeBounds = false;
        if (recycle && !src.isRecycled()) {
            src.recycle();
        }
        Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
        LogeUtil.e("yc压缩图片","压缩后大小"+bitmap.getByteCount());
        return bitmap;
    }

    /**
     * 计算获取缩放比例inSampleSize
     */
    private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;
        if (height > reqHeight || width > reqWidth) {
            final int heightRatio = Math.round((float) height / (float) reqHeight);
            final int widthRatio = Math.round((float) width / (float) reqWidth);
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
        }
        final float totalPixels = width * height;
        final float totalReqPixelsCap = reqWidth * reqHeight * 2;
        while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
            inSampleSize++;
        }
        return inSampleSize;
    }





}
